package org.layuiframework.generator.config.po;

import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import org.springframework.util.StringUtils;


import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Data
public class LayuiTableInfo  {
    @JsonIgnore
    private final Set<String> importPackages = new HashSet();
    @JsonIgnore
    private boolean convert;
    private String name;
    private String comment;
    private String entityName;
    private String mapperName;
    private String xmlName;
    private String serviceName;
    private String serviceImplName;
    private String controllerName;
    private List<LayuiTableField> fields;
    @JsonIgnore
    private boolean havePrimaryKey;
    @JsonIgnore
    private List<TableField> commonFields;
    private String fieldNames;

    private String layuiServiceName;
    private String layuiEntityName;
    @JsonIgnore
    private LayuiTableField layuiIdColumn;
    @JsonIgnore
    private LayuiTableField layuiNameColumn;
    @JsonIgnore
    private LayuiTableField layuiTimeColumn;
    private String voName;
    private String adviceName;
    private String messageHtmlName;
    @JsonIgnore
    private List<List<LayuiTableField>> layuiFields;
    private Integer layuiFieldsHeight;

    private LayuiTableField updateColumn;

    public LayuiTableInfo () {}

    public LayuiTableInfo (TableInfo tableInfo) {
        this.init(tableInfo);
    }

    private void init(TableInfo tableInfo){
        for (String packages: tableInfo.getImportPackages()) {
            this.importPackages.add(packages);
        }
        this.setConvert(tableInfo.isConvert());
        this.setName(tableInfo.getName());
        this.setComment(tableInfo.getComment());
        this.setEntityName(tableInfo.getEntityName());
        this.setMapperName(tableInfo.getMapperName());
        this.setXmlName(tableInfo.getXmlName());
        this.setServiceName(tableInfo.getServiceName());
        this.setServiceImplName(tableInfo.getServiceImplName());
        this.setControllerName(tableInfo.getControllerName());
        this.setHavePrimaryKey(tableInfo.isHavePrimaryKey());
        this.setFieldNames(tableInfo.getFieldNames());
        this.setCommonFields(tableInfo.getCommonFields());
        this.setFields(tableInfo.getFields().stream().map(m -> new LayuiTableField(m)).collect(Collectors.toList()));
        this.extendParam();
    }

    /**
     * 参数后续的处理，从tableinfo中查找到有用信息进行加工
     */
    private void extendParam(){
        /**
         * 1.添加service层的变量值
         * @desc 这个值是取的service这个类名的首字母小写，一般在controller里面引用的时候会遇到
         */
        this.setLayuiServiceName(this.decapitalize(this.getServiceName()));
        this.setLayuiEntityName(this.decapitalize(this.getEntityName()));
        /**
         * 2.查找列中的id, name, time 列
         * @desc id 在更新和删除是有重要用途，最好是指定的id  name在模糊匹配上作为条件 time 作为时间查询范围列
         */
        this.setKeyColumn();
        /**
         * 3.生成vo的class类名称
         */
        this.setVoName(this.getEntityName() + "Vo");
        /**
         * 4.生成advice的class类名称
         */
        this.setAdviceName("ControllerResponseAdvice");
        /**
         * 5.生成message的html名称
         */
        this.setMessageHtmlName(this.layuiEntityName);

        /**
         * 6. 创建layui 的添加，修改列
         */
        this.createLayuiFields();

        /**
         * 7. 查找更新列  updatetime > createtime
         */
        this.findUpdateFields();
    }

    private void createLayuiFields() {
        // 区分下单选项和多选项,两者都是不要主键属性的东西的
        // 顺序 普通 > 时间 > 下拉
        List<LayuiTableField> inputs = this.getFields().stream().filter(m -> !m.isRadioColumn() && !m.isKeyFlag() ).sorted(Comparator.comparing(LayuiTableField::isSelectColumn).thenComparing(LayuiTableField::isTimeColumn)).collect(Collectors.toList());
        // 单选
        List<LayuiTableField> radios = this.getFields().stream().filter(m -> m.isRadioColumn() && !m.isKeyFlag() ).collect(Collectors.toList());
        List<LayuiTableField> radioTemps = new ArrayList<>();
        int index = 0;
        this.setLayuiFields(new ArrayList<>());
        int point = 0;
        this.getLayuiFields().add(new ArrayList<>());
        for (LayuiTableField input: inputs) {
            if(index < 2){
                index ++;
            }else{
                index = 1;
                point ++;
                this.getLayuiFields().add(new ArrayList<>());
            }
            this.getLayuiFields().get(point).add(input);
        }
        for(LayuiTableField radio: radios){
            StringBuffer sbf = new StringBuffer();
            radio.getSource().stream().forEach(m -> sbf.append(m.getName()));
            // 内容少，可以放一行
            if(sbf.length() < 5){
                if(index < 2){
                    index ++;
                }else{
                    index = 1;
                    point ++;
                    this.getLayuiFields().add(new ArrayList<>());
                }
                this.getLayuiFields().get(point).add(radio);
            }else{
                radioTemps.add(radio);
            }
        }
        radioTemps.stream().forEach(m -> {
            List<LayuiTableField> l = new ArrayList<>();
            l.add(m);
            this.getLayuiFields().add(l);
        });
        // 上边距 + 下边距 + 提交栏 + 表单栏数量 * 45   不计算一条表单占用多行的情况
        this.setLayuiFieldsHeight( 50 + 5 + 45 + 45 * this.getLayuiFields().size() );
    }

    private void findUpdateFields(){
        AtomicReference<LayuiTableField> createTimeField = new AtomicReference();
        AtomicReference<LayuiTableField> updateTimeField = new AtomicReference();
        this.getFields().stream().filter(m -> StringUtils.hasLength(m.getFill())).forEach(m -> {
            if("INSERT".equals(m.getFill())) createTimeField.set(m);
            if("INSERT_UPDATE".equals(m.getFill())) updateTimeField.set(m);
        });
        LayuiTableField updateField = null == updateTimeField.get() ? createTimeField.get() : updateTimeField.get();
        if(null != updateField) this.updateColumn = updateField;
    }

    public static void main(String[] args) {
        List l = new ArrayList();
        l.add(new Object());

    }


    private void setKeyColumn(){
        // 第一遍，筛选注释里面指定的列
        for (LayuiTableField field: this.getFields()) {
            if(field.isIdColumn()){
                field.setIdColumn(true);
                this.setLayuiIdColumn(field);
            }
            if(field.isNameColumn()){
                field.setNameColumn(true);
                this.setLayuiNameColumn(field);
            }
            if(field.isTimeColumn()){
                field.setTimeColumn(true);
                this.setLayuiTimeColumn(field);
            }
        }
        // 第二遍，筛选同名的列
        for (LayuiTableField field: this.getFields()) {
            if(null == this.getLayuiIdColumn() && "id".equals(field.getName())){
                field.setIdColumn(true);
                this.setLayuiIdColumn(field);
            }
            if(null == this.getLayuiNameColumn() && "name".equals(field.getName())) {
                field.setNameColumn(true);
                this.setLayuiNameColumn(field);
            }
            if(null == this.getLayuiTimeColumn() && "time".equals(field.getName())){
                field.setTimeColumn(true);
                this.setLayuiTimeColumn(field);
            }
        }
        // 第三遍，顺便选一个沾点边的就行
        for (LayuiTableField field: this.getFields()) {
            if(null == this.getLayuiIdColumn() && field.getName().toLowerCase().indexOf("id") >= 0) {
                field.setIdColumn(true);
                this.setLayuiIdColumn(field);
            }
            if(null == this.getLayuiNameColumn() && field.getName().toLowerCase().indexOf("name") >= 0) {
                field.setNameColumn(true);
                this.setLayuiNameColumn(field);
            }
            if(null == this.getLayuiTimeColumn() && field.getName().toLowerCase().indexOf("time") >= 0) {
                field.setTimeColumn(true);
                this.setLayuiTimeColumn(field);
            }
        }
    }

    /**
     * 首字母转小写
     * @param name 待转化的字符串
     * @return 转化后的字符串
     */
    private String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

}
